package com.sg.fileService.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.sg.common.ResultModel;
import com.sg.common.exception.BaseBusinessException;
import com.sg.fileService.common.FileUploadTools;
import com.sg.fileService.dao.FileDataMapper;
import com.sg.fileService.entity.FileTypeConfig;
import com.sg.fileService.model.FileData;
import com.sg.fileService.service.IFileDownloadService;
import com.sg.fileService.util.ImageEncoder;
import com.sg.fileService.util.MultFileSizeUtil;
import com.sg.fileService.util.PathCreator;
import com.sg.fileService.config.Property;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class FileDownloadServiceImpl implements IFileDownloadService {
	@Autowired
	private FileDataMapper mapper;
	
	private static final String NO_FILE_IN_PATH = "此路径下未找到文件";
	
	private static final String CONTENT_DISPOSITION ="Content-Disposition";
	
	private static final String BASE_CODE="gb2312";
	
	private static final String TARGET_CODE="ISO8859-1";
	
	private static final String DISPOSITION_FILENAME_NAME="attachment; filename=";
	
	@Override
	public void downloadFileByPath(HttpServletResponse response, String filePath,String fileType) throws BaseBusinessException {
		filePath = PathCreator.getTargetFilePath(filePath, fileType);
		FileTypeConfig fileTypeConfig = FileUploadTools.getTypeConfig0(filePath);
		//如果不是下载原始文件，
		//并且文件类型不为空，
		//并且文件上传后进行统一转码的，
		//则更改文件后缀为统一转码后缀，
		//否则使用源文件路径
		if(!Property.LAST_PATH_O.equals(fileType)
				&&!StringUtils.isEmpty(fileType)
				&&fileTypeConfig.getEncodeAble()){
			filePath = PathCreator.modifyFileSuffix(filePath, fileTypeConfig.getFormatType());
		}
		
		doDownLoad(response,filePath);
	}
	
	@Override
	public void downloadFileById(HttpServletResponse response, String fileId,String fileType) throws BaseBusinessException {

		//根据fileId查询数据库获取fileData数据
		FileData fileData = mapper.queryById(fileId);
		if(fileData!=null){
			downloadFileByPath(response,fileData.getFilePath(),fileType);
		}
	}
	

	

	@Override
	public void transcoingAndDownloadImgByPath(HttpServletResponse response, String sourceFilePath
			,String fileType,String tranType) throws BaseBusinessException {
		
		//根据文件路径中的名称，获取文件配置信息
		FileTypeConfig fileTypeConfig = FileUploadTools.getTypeConfig0(sourceFilePath);
		//如果配置中设置为不进行图片转换，则直接进行实时转换
		if(fileTypeConfig.getEncodeAble()) {
			//1、路径修改。如果配置中进行转换，则拼接转换文件的文件路径
			sourceFilePath = PathCreator.getTargetFilePath(sourceFilePath, fileType);
			//2、后缀修改。如果不是下载原始文件并且文件类型不为空，把后缀修改成统一配置的转换格式
			if(!Property.LAST_PATH_O.equals(fileType)&&!StringUtils.isEmpty(fileType)){
				sourceFilePath = PathCreator.modifyFileSuffix(sourceFilePath,Property.IMG_FORMAT_TYPE);
			}
			if(new File(sourceFilePath).exists()) {
				//如果目标文件路径存在文件
				//进行转换
				if(!"original".equals(tranType)) {
					//如果不是源文件下载，则进行文件转换
					doImgTranscoingAndDownLoad(response,sourceFilePath,tranType);
				}else {
					//如果是源文件下载，则直接通过文件路径下载
					doDownLoad(response,sourceFilePath);
				}
			}else {
				//如果母校文件路径不存在文件
				//进行实时转换
				doTranscoingAndZoomAndDownloadImg(response,sourceFilePath,fileType,tranType);
			}
		}else {
			//如果配置中没有设置图片转换，则直接进行实时转换
			doTranscoingAndZoomAndDownloadImg(response,sourceFilePath,fileType,tranType);
		}
	}
	
	@Override
	public void transcoingAndDownloadImgById(HttpServletResponse response, String fileId
			,String fileType,String tranType) throws BaseBusinessException {
		FileData fileData = mapper.queryById(fileId);
		if(fileData!=null) {
			//如果数据库存在此数据，则通过数据中的文件路径，调用文件路径下载方法
			transcoingAndDownloadImgByPath(response,fileData.getFilePath(),fileType,tranType);
		}else {
			//没有此数据则进行无法发现处理
			notFindFileError(response,"文件数据不存在");
		}
	}
	
	/**
	 * 文件转换格式并下载
	 * @param response
	 * 			响应
	 * @param filePath
	 * 			文件路径
	 * @param tranType
	 * 			文件转换类型
	 * @throws IOException
	 */
	private static void doImgTranscoingAndDownLoad(HttpServletResponse response, String filePath,String tranType) throws BaseBusinessException {

		String path = PathCreator.getFilePathByRealTivePath(filePath);
		File file = new File(path);
		if(!file.exists() || !file.isFile())
		{
			notFindFileError(response,NO_FILE_IN_PATH);
		}else{
			String filename = file.getName().substring(0, file.getName().lastIndexOf('.')+1)+tranType;
			try{ 
		        response.setHeader(CONTENT_DISPOSITION,DISPOSITION_FILENAME_NAME 
			                       + new String(filename.getBytes(BASE_CODE),TARGET_CODE)); 
				//转换并传输下载
				ImageEncoder.toTranscodingAndOutput(path, tranType, response.getOutputStream());
			}catch(Exception e){
				log.error("文件{}转码{}下载失败：{}",filePath,tranType,e.getMessage());
				throw new BaseBusinessException("文件转码下载失败");
			}
		}
	}
	

	
	//图片的实时格式转化，缩放，下载
	private void doTranscoingAndZoomAndDownloadImg(HttpServletResponse response, String sourceFilePath
			,String fileType,String tranType) throws BaseBusinessException {
		MultFileSizeUtil fileSizeUtil = new MultFileSizeUtil();
		if(!Property.LAST_PATH_O.equals(fileType)) {
			//获取文件宽高
			MultFileSizeUtil.FileSize fileSize = fileSizeUtil.getImgSizeByFileType(fileType);
			//如果没有图片自动转换，则需要对文件进行转换并进行fileType对应的缩放
			doImgTranscoingAndZoomAndDownLoad(response,sourceFilePath,tranType,fileSize.getWidth(),fileSize.getHeight());
		}else {
			doImgTranscoingAndDownLoad(response,sourceFilePath,tranType);
		}
	}
	
	/**
	 * 文件转换格式，缩放，并下载
	 * @param response
	 * 			响应
	 * @param filePath
	 * 			文件路径
	 * @param width
	 * 			文件宽
	 * @param height
	 * 			文件高
	 * @param tranType
	 * 			文件转换类型
	 * @throws IOException
	 */
	private static void doImgTranscoingAndZoomAndDownLoad(HttpServletResponse response, String filePath,String tranType,int height,int width) throws BaseBusinessException {
		String path = PathCreator.getFilePathByRealTivePath(filePath);
		File file = new File(path);
		if(!file.exists() || !file.isFile())
		{
			notFindFileError(response,NO_FILE_IN_PATH);
		}else{
			String filename = file.getName().substring(0, file.getName().lastIndexOf('.')+1)+tranType;
			try{ 

		        response.setHeader(CONTENT_DISPOSITION,DISPOSITION_FILENAME_NAME 
			                       + new String(filename.getBytes(BASE_CODE),TARGET_CODE)); 
			}catch(Exception e){
				log.error(e.getMessage());
			}
			try {
				//转换并传输下载
				ImageEncoder.toTranscodingAndZoomAndOutput(path, tranType,width,height, response.getOutputStream());
			}catch(IOException e) {
				log.error("文件{}转码{}下载失败：{}",filePath,tranType,e.getMessage());
				throw new BaseBusinessException("文件转码传输失败");
			}
		}
	}
	
	
	
	/**
	 * 文件下载
	 * @param response
	 * 			响应
	 * @param filePath
	 * 			文件路径
	 */
	private static void doDownLoad(HttpServletResponse response, String filePath){
		 //拼接文件路径
		String path = PathCreator.getFilePathByRealTivePath(filePath);
		File file = new File(path);
		if(!file.exists() || !file.isFile())
		{
			notFindFileError(response,NO_FILE_IN_PATH);
		}else{
			String filename = file.getName();
			try{ 
		        response.setHeader(CONTENT_DISPOSITION,DISPOSITION_FILENAME_NAME 
	                       + new String(filename.getBytes(BASE_CODE),TARGET_CODE)); 
			}catch(Exception e){
				log.error(e.getMessage());
			}
			
			try(
				InputStream in = new FileInputStream(path);
				OutputStream out = response.getOutputStream();
			   )
			{
				int len = 0;
				byte[] buffer = new byte[1024];
				
				while ((len = in.read(buffer)) > 0)
				{
					out.write(buffer, 0, len);
				}

			}
			catch (Exception e)
			{
				log.error(e.getMessage());
			}
		}
	}
	
	private static void notFindFileError(HttpServletResponse response,String msg) {
		try {
			response.setHeader("Content-type", "application/Json;charset=UTF-8");
			ResultModel result = new ResultModel(false, "", msg, null);
			response.getWriter().print(JSONObject.toJSONString(result));
		} catch (IOException e) {
			log.error(e.getMessage());
		}
	}

}
